1 : <?php
2 : /**
3 : * Container implementation.
4 : *
5 : * PHP Version 5
6 : *
7 : * @category Ding
8 : * @package Container
9 : * @subpackage Impl
10 : * @author Marcelo Gornstein <marcelog@gmail.com>
11 : * @license http://marcelog.github.com/ Apache License 2.0
12 : * @link http://marcelog.github.com/
13 : *
14 : * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
15 : *
16 : * Licensed under the Apache License, Version 2.0 (the "License");
17 : * you may not use this file except in compliance with the License.
18 : * You may obtain a copy of the License at
19 : *
20 : * http://www.apache.org/licenses/LICENSE-2.0
21 : *
22 : * Unless required by applicable law or agreed to in writing, software
23 : * distributed under the License is distributed on an "AS IS" BASIS,
24 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 : * See the License for the specific language governing permissions and
26 : * limitations under the License.
27 : *
28 : */
29 : namespace Ding\Container\Impl;
30 :
31 : use Ding\Helpers\ErrorHandler\ErrorInfo;
32 :
33 : use Ding\Bean\IBeanDefinitionProvider;
34 : use Ding\Cache\Impl\DummyCacheImpl;
35 : use Ding\Bean\Provider\Core;
36 : use Ding\Resource\Impl\IncludePathResource;
37 : use Ding\Resource\Impl\FilesystemResource;
38 : use Ding\Resource\Impl\URLResource;
39 : use Ding\Cache\Locator\CacheLocator;
40 : use Ding\Container\IContainer;
41 : use Ding\Aspect\AspectManager;
42 : use Ding\Aspect\InterceptorDefinition;
43 : use Ding\Aspect\AspectDefinition;
44 : use Ding\Aspect\Interceptor\IDispatcher;
45 : use Ding\Aspect\Interceptor\DispatcherImpl;
46 : use Ding\Reflection\ReflectionFactory;
47 : use Ding\Bean\Lifecycle\BeanLifecycle;
48 : use Ding\Bean\Lifecycle\BeanLifecycleManager;
49 : use Ding\Bean\Factory\Exception\BeanFactoryException;
50 : use Ding\Bean\BeanConstructorArgumentDefinition;
51 : use Ding\Bean\BeanDefinition;
52 : use Ding\Bean\BeanPropertyDefinition;
53 : use Ding\MessageSource\IMessageSource;
54 :
55 : /**
56 : * Container implementation.
57 : *
58 : * PHP Version 5
59 : *
60 : * @category Ding
61 : * @package Container
62 : * @subpackage Impl
63 : * @author Marcelo Gornstein <marcelog@gmail.com>
64 : * @license http://marcelog.github.com/ Apache License 2.0
65 : * @link http://marcelog.github.com/
66 : */
67 : class ContainerImpl implements IContainer
68 : {
69 : /**
70 : * Signals to handle.
71 : * @var array
72 : */
73 : private $_signals = array(
74 : SIGQUIT, SIGHUP, SIGINT, SIGCHLD, SIGTERM, SIGUSR1, SIGUSR2
75 : );
76 : /**
77 : * Logger.
78 : * @var Logger
79 : */
80 : private $_logger;
81 :
82 : /**
83 : * Cache for isDebugEnabled()
84 : * @var boolean
85 : */
86 : private $_logDebugEnabled;
87 :
88 : /**
89 : * Dispatcher to be cloned for proxy.
90 : * @var DispatcherImpl
91 : */
92 : private $_dispatcherTemplate = null;
93 :
94 : /**
95 : * MessageSource implementation.
96 : * @var IMessageSource
97 : */
98 : private $_messageSource = false;
99 : /**
100 : * Default options.
101 : * @var array
102 : */
103 : private static $_options = array(
104 : 'bdef' => array(),
105 : 'properties' => array(),
106 : 'drivers' => array()
107 : );
108 :
109 : /**
110 : * Registered shutdown methods for beans (destroy-methods).
111 : * @var array
112 : */
113 : private $_shutdowners = array();
114 :
115 : /**
116 : * Beans already instantiated.
117 : * @var object[]
118 : */
119 : private $_beans;
120 :
121 : /**
122 : * Holds our beans cache.
123 : * @var ICache
124 : */
125 : private $_beanCache;
126 :
127 : /**
128 : * Beans already instantiated.
129 : * @var BeanDefinition[]
130 : */
131 : private $_beanDefs;
132 :
133 : /**
134 : * Beans aliases.
135 : * @var string[]
136 : */
137 : private $_beanAliases;
138 :
139 : /**
140 : * Holds our bean definitions cache.
141 : * @var ICache
142 : */
143 : private $_beanDefCache;
144 :
145 : /**
146 : * Container instance.
147 : * @var ContainerImpl
148 : */
149 : private static $_containerInstance = false;
150 :
151 : /**
152 : * The aspect manager.
153 : * @var AspectManager
154 : */
155 : private $_aspectManager = null;
156 :
157 : /**
158 : * The lifecycle manager.
159 : * @var BeanLifecycleManager
160 : */
161 : private $_lifecycleManager = null;
162 :
163 : /**
164 : * Resources multiton.
165 : * @var IResource[]
166 : */
167 : private $_resources = false;
168 :
169 : /**
170 : * The event listeners
171 : * @var string[]
172 : */
173 : private $_eventListeners = false;
174 :
175 : /**
176 : * Bean Definition providers.
177 : * @var IBeanDefinitionProvider[]
178 : */
179 : private $_beanDefinitionProviders = array();
180 :
181 : /**
182 : * The last error message is saved, just to avoid logging repeated messages.
183 : * @var string
184 : */
185 : private $_lastErrorMessage;
186 :
187 : /**
188 : * A ReflectionFactory implementation
189 : * @var IReflectionFactory
190 : */
191 : private $_reflectionFactory;
192 :
193 : /**
194 : * A Proxy factory implementation.
195 : * @var Proxy
196 : */
197 : private $_proxyFactory;
198 :
199 : /**
200 : * Properties configured when instantiating the container and by others,
201 : * like when using a PropertiesHolder.
202 : *
203 : * @var string[]
204 : */
205 : private $_properties;
206 :
207 : /**
208 : * Prevent serialization.
209 : *
210 : * @return array
211 : */
212 : public function __sleep()
213 : {
214 1 : return array('_aspectManager', '_lifecycleManager');
215 : }
216 :
217 : /**
218 : * (non-PHPdoc)
219 : * @see Ding\Bean.IBeanDefinitionProvider::getBeanDefinitionByClass()
220 : */
221 : public function getBeanDefinitionByClass($class)
222 : {
223 3 : foreach ($this->_beanDefinitionProviders as $provider) {
224 3 : $beanDefinition = $provider->getBeanDefinitionByClass($class);
225 3 : }
226 3 : }
227 : /**
228 : * Returns a bean definition.
229 : *
230 : * @param string $name Bean name.
231 : *
232 : * @return BeanDefinition
233 : * @throws BeanFactoryException
234 : */
235 : public function getBeanDefinition($name)
236 : {
237 276 : $beanName = $name . '.beandef';
238 276 : if (isset($this->_beanAliases[$name])) {
239 1 : $name = $this->_beanAliases[$name];
240 1 : }
241 276 : if (isset($this->_beanDefs[$name])) {
242 41 : return $this->_beanDefs[$name];
243 : }
244 :
245 276 : $beanDefinition = null;
246 276 : if ($this->_beanDefCache !== null) {
247 276 : $beanDefinition = $this->_beanDefCache->fetch($beanName, $result);
248 276 : }
249 276 : if ($beanDefinition) {
250 69 : $this->_beanDefs[$name] = $beanDefinition;
251 69 : return $beanDefinition;
252 : }
253 276 : foreach ($this->_beanDefinitionProviders as $provider) {
254 276 : $beanDefinition = $provider->getBeanDefinition($name);
255 276 : if ($beanDefinition) {
256 276 : $beanDefinition->setClass($this->_searchAndReplaceProperties(
257 276 : $beanDefinition->getClass()
258 276 : ));
259 276 : break;
260 : }
261 276 : }
262 276 : if (!$beanDefinition) {
263 258 : throw new BeanFactoryException('Unknown bean: ' . $name);
264 : }
265 276 : $beanDefinition = $this->_lifecycleManager->afterDefinition($beanDefinition);
266 276 : $this->_beanDefs[$beanName] = $beanDefinition;
267 276 : $this->_beanDefCache->store($beanName, $beanDefinition);
268 276 : foreach ($beanDefinition->getAliases() as $alias) {
269 18 : $this->_beanAliases[$alias] = $name;
270 276 : }
271 276 : return $beanDefinition;
272 : }
273 :
274 : /**
275 : * Will try to search and replace the properties found in the given
276 : * value.
277 : *
278 : * @param string $value
279 : *
280 : * @return string
281 : */
282 : private function _searchAndReplaceProperties($value)
283 : {
284 276 : if (is_string($value)) {
285 276 : foreach ($this->_properties as $k => $v) {
286 48 : if (strpos($value, $k) !== false) {
287 19 : if (is_string($v)) {
288 19 : $value = str_replace($k, $v, $value);
289 19 : } else {
290 12 : $value = $v;
291 : // Assigned value is not a string, so we cant use
292 : // strpos anymore on it (i.e: cant continue replacing)
293 12 : break;
294 : }
295 19 : }
296 276 : }
297 276 : }
298 276 : return $value;
299 : }
300 :
301 : /**
302 : * Takes care of transforming a scalar value for a property or constructor
303 : * argument, into a an actual value (i.e: if its a resource://, loading it
304 : * first).
305 : *
306 : * @param mixed $value The value
307 : *
308 : * @return mixed
309 : */
310 : private function _loadValue($value)
311 : {
312 276 : $value = $this->_searchAndReplaceProperties($value);
313 276 : if (is_string($value) && strpos($value, 'resource://') === 0) {
314 2 : $value = substr($value, 11);
315 2 : return $this->getResource($value);
316 : }
317 276 : return $value;
318 : }
319 :
320 : /**
321 : * This will resolve a property (or constructor arg) definition to a final
322 : * value, being a bean reference, array of other properties (or
323 : * constructor args), etc.
324 : *
325 : * @param BeanPropertyDefinition|BeanConstructorArgumentDefinition $what
326 : *
327 : * @return void
328 : */
329 : private function _getValueFromDefinition($what)
330 : {
331 276 : $value = null;
332 276 : if ($what->isBean()) {
333 276 : $value = $this->getBean($what->getValue());
334 276 : } else if ($what->isArray()) {
335 53 : $value = array();
336 53 : foreach ($what->getValue() as $k => $v) {
337 53 : $value[$k] = $this->_getValueFromDefinition($v);
338 53 : }
339 276 : } else if ($what->isCode()) {
340 24 : $value = eval($what->getValue());
341 24 : } else {
342 276 : $value = $this->_loadValue($what->getValue());
343 : }
344 276 : return $value;
345 : }
346 :
347 : /**
348 : * Resolves all values for constructor arguments definitions in a
349 : * bean definition.
350 : *
351 : * @param BeanDefinition $definition
352 : *
353 : * @return object
354 : */
355 : private function _getConstructorValuesForDefinition($definition)
356 : {
357 276 : $args = array();
358 276 : foreach ($definition->getArguments() as $argument) {
359 276 : $value = $this->_getValueFromDefinition($argument);
360 276 : if ($argument->hasName()) {
361 4 : $name = $argument->getName();
362 4 : $args[$name] = $value;
363 4 : } else {
364 276 : $args[] = $value;
365 : }
366 276 : }
367 276 : return $args;
368 : }
369 :
370 : /**
371 : * Instantiates a bean using the constructor.
372 : *
373 : * @param BeanDefinition $definition
374 : *
375 : * @return object
376 : */
377 : private function _instantiateByConstructor(BeanDefinition $definition)
378 : {
379 276 : $class = $definition->getClass();
380 276 : if ($definition->hasProxyClass()) {
381 24 : $class = $definition->getProxyClassName();
382 24 : }
383 276 : $rClass = $this->_reflectionFactory->getClass($class);
384 276 : $factoryMethod = $rClass->getConstructor();
385 276 : if ($factoryMethod !== null) {
386 276 : $args = $this->_sortArgsWithNames($definition, $factoryMethod);
387 276 : if (empty($args)) {
388 276 : return $rClass->newInstanceArgs();
389 : } else {
390 276 : return $rClass->newInstanceArgs($args);
391 : }
392 : } else {
393 276 : return $rClass->newInstanceArgs();
394 : }
395 : }
396 :
397 : /**
398 : * Instantiates a bean using a factory class.
399 : *
400 : * @param BeanDefinition $definition
401 : *
402 : * @return object
403 : */
404 : private function _instantiateByFactoryClass(BeanDefinition $definition)
405 : {
406 276 : $class = $definition->getClass();
407 276 : $rClass = $this->_reflectionFactory->getClass($class);
408 276 : $factoryMethodName = $definition->getFactoryMethod();
409 276 : $factoryMethod = $rClass->getMethod($factoryMethodName);
410 276 : $args = $this->_sortArgsWithNames($definition, $factoryMethod);
411 276 : return forward_static_call_array(array($class, $factoryMethodName), $args);
412 : }
413 :
414 : /**
415 : * Instantiates a bean using a factory bean.
416 : *
417 : * @param BeanDefinition $definition
418 : *
419 : * @return object
420 : */
421 : private function _instantiateByFactoryBean(BeanDefinition $definition)
422 : {
423 68 : $factoryBean = $this->getBean($definition->getFactoryBean());
424 68 : $refObject = new \ReflectionObject($factoryBean);
425 68 : $factoryMethod = $refObject->getMethod($definition->getFactoryMethod());
426 68 : $args = $this->_sortArgsWithNames($definition, $factoryMethod);
427 68 : return $factoryMethod->invokeArgs($factoryBean, $args);
428 : }
429 :
430 : private function _sortArgsWithNames(BeanDefinition $definition, \ReflectionMethod $rMethod)
431 : {
432 276 : $args = $this->_getConstructorValuesForDefinition($definition);
433 276 : $callArgs = array();
434 276 : foreach ($rMethod->getParameters() as $parameter) {
435 276 : $parameterName = $parameter->getName();
436 276 : if (isset($args[$parameterName])) {
437 4 : $callArgs[] = $args[$parameterName];
438 4 : unset($args[$parameterName]);
439 4 : }
440 276 : }
441 276 : foreach ($args as $value) {
442 276 : $callArgs[] = $value;
443 276 : }
444 276 : return $callArgs;
445 : }
446 :
447 : /**
448 : * Instantiates a bean.
449 : *
450 : * @param BeanDefinition $definition
451 : *
452 : * @return object
453 : */
454 : private function _instantiate(BeanDefinition $definition)
455 : {
456 276 : if ($definition->isCreatedByConstructor()) {
457 276 : return $this->_instantiateByConstructor($definition);
458 276 : } else if ($definition->isCreatedWithFactoryBean()) {
459 68 : return $this->_instantiateByFactoryBean($definition);
460 : } else {
461 276 : return $this->_instantiateByFactoryClass($definition);
462 : }
463 : }
464 :
465 : /**
466 : * Creates whatever beans this definition depends on.
467 : *
468 : * @return void
469 : */
470 : private function _createBeanDependencies(BeanDefinition $definition)
471 : {
472 276 : foreach ($definition->getDependsOn() as $depBean) {
473 6 : $this->getBean(trim($depBean));
474 276 : }
475 276 : }
476 :
477 : /**
478 : * Will inject into the given dispatcher the necessary information to
479 : * aspects will be run correctly.
480 : *
481 : * @throws BeanFactoryException
482 : * @return void
483 : */
484 : private function _applyAspect(
485 : $targetClass, AspectDefinition $aspectDefinition, IDispatcher $dispatcher
486 : ) {
487 25 : $rClass = $this->_reflectionFactory->getClass($targetClass);
488 25 : $aspect = $this->getBean($aspectDefinition->getBeanName());
489 25 : foreach ($aspectDefinition->getPointcuts() as $pointcutName) {
490 25 : $pointcut = $this->_aspectManager->getPointcut($pointcutName);
491 25 : if ($pointcut === false) {
492 1 : throw new BeanFactoryException('Could not find pointcut: ' . $pointcutName);
493 : }
494 24 : $expression = $pointcut->getExpression();
495 24 : foreach ($rClass->getMethods() as $method) {
496 24 : $methodName = $method->getName();
497 24 : if (preg_match('/' . $expression . '/', $methodName) === 0) {
498 8 : continue;
499 : }
500 : if (
501 24 : $aspectDefinition->getType() == AspectDefinition::ASPECT_METHOD
502 24 : ) {
503 21 : $dispatcher->addMethodInterceptor($methodName, $aspect, $pointcut->getMethod());
504 21 : } else {
505 5 : $dispatcher->addExceptionInterceptor($methodName, $aspect, $pointcut->getMethod());
506 : }
507 24 : }
508 24 : }
509 24 : }
510 :
511 : /**
512 : * Applies all aspects specifically defined for this bean definition.
513 : *
514 : * @param BeanDefinition $definition
515 : * @param IDispatcher $dispatcher
516 : *
517 : * @return void
518 : */
519 : private function _applySpecificAspects(BeanDefinition $definition, IDispatcher $dispatcher)
520 : {
521 276 : if ($definition->hasAspects()) {
522 17 : foreach ($definition->getAspects() as $aspect) {
523 17 : $this->_applyAspect($definition->getClass(), $aspect, $dispatcher);
524 17 : }
525 17 : }
526 276 : }
527 :
528 : /**
529 : * Looks for any global aspects that may apply to this bean and applies them.
530 : *
531 : * @param BeanDefinition $definition
532 : * @param IDispatcher $dispatcher
533 : *
534 : * @return void
535 : */
536 : private function _applyGlobalAspects(BeanDefinition $definition, IDispatcher $dispatcher)
537 : {
538 276 : $class = $definition->getClass();
539 276 : $rClass = $this->_reflectionFactory->getClass($class);
540 276 : foreach ($this->_aspectManager->getAspects() as $aspect) {
541 29 : $expression = $aspect->getExpression();
542 29 : if (preg_match('/' . $expression . '/', $class) === 0) {
543 29 : $parentClass = $rClass->getParentClass();
544 29 : while($parentClass !== false) {
545 1 : if (preg_match('/' . $expression . '/', $parentClass->getName()) > 0) {
546 1 : $this->_applyAspect($class, $aspect, $dispatcher);
547 1 : }
548 1 : $parentClass = $parentClass->getParentClass();
549 1 : }
550 29 : } else {
551 7 : $this->_applyAspect($class, $aspect, $dispatcher);
552 : }
553 276 : }
554 276 : }
555 :
556 : /**
557 : * Applies specific bean aspects and global defined aspects.
558 : *
559 : * @param BeanDefinition $definition
560 : *
561 : * @return void
562 : */
563 : private function _applyAspects(BeanDefinition $definition)
564 : {
565 276 : $class = $definition->getClass();
566 276 : $dispatcher = clone $this->_dispatcherTemplate;
567 276 : $this->_applySpecificAspects($definition, $dispatcher);
568 276 : $this->_applyGlobalAspects($definition, $dispatcher);
569 276 : if ($dispatcher->hasMethodsIntercepted()) {
570 24 : $definition->setProxyClassName(
571 24 : $this->_proxyFactory->create($class, $dispatcher)
572 24 : );
573 24 : }
574 276 : }
575 : /**
576 : * This will create a new bean, injecting all properties and applying all
577 : * aspects.
578 : *
579 : * @throws BeanFactoryException
580 : * @return object
581 : */
582 : private function _createBean(BeanDefinition $definition)
583 : {
584 276 : $this->_lifecycleManager->beforeCreate($definition);
585 276 : $this->_createBeanDependencies($definition);
586 276 : $this->_applyAspects($definition);
587 276 : $bean = $this->_instantiate($definition);
588 276 : if (!is_object($bean)) {
589 1 : throw new BeanFactoryException(
590 1 : 'Could not instantiate ' . $definition->getName()
591 1 : );
592 : }
593 276 : $this->_assemble($bean, $definition);
594 276 : $this->_setupInitAndShutdown($bean, $definition);
595 276 : $this->_lifecycleManager->afterCreate($bean, $definition);
596 276 : return $bean;
597 : }
598 :
599 : /**
600 : * Calls init method and register shutdown method.
601 : *
602 : * @param object $bean
603 : * @param BeanDefinition $definition
604 : *
605 : * @return void
606 : */
607 : private function _setupInitAndShutdown($bean, BeanDefinition $definition)
608 : {
609 276 : if ($definition->hasInitMethod()) {
610 33 : $initMethod = $definition->getInitMethod();
611 33 : $bean->$initMethod();
612 33 : }
613 276 : if ($definition->hasDestroyMethod()) {
614 32 : $destroyMethod = $definition->getDestroyMethod();
615 32 : $this->registerShutdownMethod($bean, $destroyMethod);
616 32 : }
617 276 : }
618 :
619 : /**
620 : * Tries to inject by looking up set* methods.
621 : *
622 : * @param object $bean
623 : * @param string $name
624 : * @param string $value
625 : *
626 : * @return boolean
627 : */
628 : private function _setterInject($bean, $name, $value)
629 : {
630 276 : $methodName = 'set' . ucfirst($name);
631 276 : $rClass = $this->_reflectionFactory->getClass(get_class($bean));
632 276 : if ($rClass->hasMethod($methodName)) {
633 276 : $bean->$methodName($value);
634 276 : return true;
635 : }
636 18 : return false;
637 : }
638 :
639 : /**
640 : * Tries to inject by looking up a property by name.
641 : *
642 : * @param object $bean
643 : * @param string $name
644 : * @param string $value
645 : *
646 : * @return boolean
647 : */
648 : private function _propertyInject($bean, $name, $value)
649 : {
650 18 : $rClass = $this->_reflectionFactory->getClass(get_class($bean));
651 18 : if ($rClass->hasProperty($name)) {
652 17 : $rProperty = $rClass->getProperty($name);
653 17 : if (!$rProperty->isPublic()) {
654 11 : $rProperty->setAccessible(true);
655 11 : }
656 17 : $rProperty->setValue($bean, $value);
657 17 : return true;
658 : }
659 1 : return false;
660 : }
661 : /**
662 : * Assembles a bean (setter injection)
663 : *
664 : * @param mixed $bean
665 : * @param BeanDefinition $beanDefinition
666 : *
667 : * @return void
668 : */
669 : private function _assemble($bean, BeanDefinition $beanDefinition)
670 : {
671 276 : $this->_lifecycleManager->beforeAssemble($bean, $beanDefinition);
672 276 : foreach ($beanDefinition->getProperties() as $property) {
673 276 : $propertyName = $property->getName();
674 276 : $propertyValue = $this->_getValueFromDefinition($property);
675 : if (
676 276 : $this->_setterInject($bean, $propertyName, $propertyValue)
677 18 : || $this->_propertyInject($bean, $propertyName, $propertyValue)
678 276 : ) {
679 276 : continue;
680 : }
681 1 : throw new BeanFactoryException("Dont know how to inject: $propertyName");
682 276 : }
683 276 : $this->fillAware($beanDefinition, $bean);
684 276 : $this->_lifecycleManager->afterAssemble($bean, $beanDefinition);
685 276 : }
686 : /**
687 : * Returns a bean.
688 : *
689 : * @param string $name Bean name.
690 : *
691 : * @throws BeanFactoryException
692 : * @return object
693 : */
694 : public function getBean($name)
695 : {
696 276 : $ret = false;
697 276 : $beanDefinition = $this->getBeanDefinition($name);
698 276 : $beanName = $name . '.bean';
699 276 : if ($beanDefinition->isAbstract()) {
700 1 : throw new BeanFactoryException(
701 1 : "Cant instantiate abstract bean: $name"
702 1 : );
703 : }
704 276 : if ($beanDefinition->isPrototype()) {
705 38 : $ret = $this->_createBean($beanDefinition);
706 276 : } else if ($beanDefinition->isSingleton()) {
707 276 : if (isset($this->_beans[$beanName])) {
708 174 : $ret = $this->_beans[$beanName];
709 174 : } else {
710 276 : $ret = $this->_beanCache->fetch($beanName, $result);
711 276 : if (!$ret) {
712 276 : $ret = $this->_createBean($beanDefinition);
713 276 : }
714 276 : $this->_beans[$beanName] = $ret;
715 : }
716 276 : }
717 276 : return $ret;
718 : }
719 :
720 : /**
721 : * This will return a container
722 : *
723 : * @param array $properties Container properties.
724 : *
725 : * @return ContainerImpl
726 : */
727 : public static function getInstance(array $properties = array())
728 : {
729 276 : if (self::$_containerInstance === false) {
730 : // Init cache subsystems.
731 276 : if (isset($properties['ding']['cache'])) {
732 158 : CacheLocator::configure($properties['ding']['cache']);
733 158 : }
734 276 : \Ding\Autoloader\Autoloader::setCache(CacheLocator::getAutoloaderCacheInstance());
735 276 : if (isset($properties['ding']['log4php.properties'])) {
736 276 : \Logger::configure($properties['ding']['log4php.properties']);
737 276 : }
738 276 : self::$_containerInstance = new ContainerImpl($properties['ding']['factory']);
739 272 : }
740 272 : return self::$_containerInstance;
741 : }
742 :
743 : /**
744 : * Register a shutdown (destroy-method) method for a bean.
745 : *
746 : * @param object $bean Bean to call.
747 : * @param string $method Method to call.
748 : *
749 : * @see Ding\Container.IContainer::registerShutdownMethod()
750 : *
751 : * @return void
752 : */
753 : public function registerShutdownMethod($bean, $method)
754 : {
755 32 : $this->_shutdowners[] = array($bean, $method);
756 32 : }
757 :
758 : /**
759 : * Destructor, will call all beans destroy-methods.
760 : *
761 : * @return void
762 : */
763 : public function __destruct()
764 : {
765 16 : foreach ($this->_shutdowners as $shutdownCall) {
766 16 : $bean = $shutdownCall[0];
767 16 : $method = $shutdownCall[1];
768 16 : $bean->$method();
769 16 : }
770 16 : }
771 :
772 : /**
773 : *
774 : * Enter description here ...
775 : * @param unknown_type $messageSource
776 : */
777 : public function setMessageSource(IMessageSource $messageSource)
778 : {
779 14 : $this->_messageSource = $messageSource;
780 14 : }
781 :
782 : /**
783 : * (non-PHPdoc)
784 : * @see Ding\MessageSource.IMessageSource::getMessage()
785 : */
786 : public function getMessage($bundle, $message, array $arguments, $locale = 'default')
787 : {
788 : return
789 3 : $this->_messageSource !== false
790 3 : ? $this->_messageSource->getMessage($bundle, $message, $arguments, $locale)
791 3 : : NULL;
792 : }
793 :
794 : /**
795 : * (non-PHPdoc)
796 : * @see Ding\Resource.IResourceLoader::getResource()
797 : */
798 : public function getResource($location, $context = false)
799 : {
800 : // Missing scheme?
801 8 : $scheme = strpos($location, '://');
802 8 : if ($scheme === false) {
803 1 : $location = FilesystemResource::SCHEME . $location;
804 1 : }
805 : // Already served?
806 8 : if (isset($this->_resources[$location])) {
807 1 : return $this->_resources[$location];
808 : }
809 : // See what kind of resource to return.
810 8 : if (strpos($location, FilesystemResource::SCHEME) === 0) {
811 3 : $resource = new FilesystemResource($location, $context);
812 8 : } else if (strpos($location, IncludePathResource::SCHEME) === 0) {
813 4 : $resource = new IncludePathResource($location, $context);
814 4 : } else {
815 1 : $resource = new URLResource($location, $context);
816 : }
817 8 : $this->_resources[$location] = $resource;
818 8 : return $resource;
819 : }
820 :
821 : /**
822 : * (non-PHPdoc)
823 : * @see Ding\Container.IContainer::eventDispatch()
824 : */
825 : public function eventDispatch($eventName, $data = null)
826 : {
827 14 : $eventName = 'on' . ucfirst($eventName);
828 14 : if (isset($this->_eventListeners[$eventName])) {
829 5 : foreach ($this->_eventListeners[$eventName] as $beanName) {
830 5 : $bean = $this->getBean($beanName);
831 5 : $bean->$eventName($data);
832 5 : }
833 5 : }
834 14 : }
835 :
836 : /**
837 : * (non-PHPdoc)
838 : * @see Ding\Container.IContainer::eventListen()
839 : */
840 : public function eventListen($eventName, $beanName)
841 : {
842 7 : if (!isset($this->_eventListeners[$eventName])) {
843 7 : $this->_eventListeners[$eventName] = array();
844 7 : }
845 7 : $eventName = 'on' . ucfirst($eventName);
846 7 : $this->_eventListeners[$eventName][] = $beanName;
847 7 : }
848 :
849 : /**
850 : * (non-PHPdoc)
851 : * @see Ding\Container.IContainer::registerBeanDefinitionProvider()
852 : */
853 : public function registerBeanDefinitionProvider(IBeanDefinitionProvider $provider)
854 : {
855 276 : $this->_beanDefinitionProviders[] = $provider;
856 276 : }
857 :
858 : /**
859 : * If we dont have a ReflectionFactory yet (i.e: didnt make the call to
860 : * getBean() yet), replace it with this one.
861 : *
862 : * @param string $class The name of a class.
863 : *
864 : * @return ReflectionClass
865 : */
866 : protected function getClass($class)
867 : {
868 276 : return new \ReflectionClass($class);
869 : }
870 :
871 : /**
872 : * Will look for "aware" kind of interfaces and inject whatever necessary.
873 : *
874 : * @param BeanDefinition $def The Bean Definition
875 : * @param object $bean The bean
876 : *
877 : * @return void
878 : */
879 : public function fillAware(BeanDefinition $def, $bean)
880 : {
881 276 : $class = get_class($bean);
882 276 : $rClass = $this->_reflectionFactory->getClass($class);
883 276 : if ($rClass->implementsInterface('Ding\Reflection\IReflectionFactoryAware')) {
884 276 : $bean->setReflectionFactory($this->_reflectionFactory);
885 276 : }
886 276 : if ($rClass->implementsInterface('Ding\Bean\IBeanNameAware')) {
887 1 : $bean->setBeanName($def->getName());
888 1 : }
889 276 : if ($rClass->implementsInterface('Ding\Logger\ILoggerAware')) {
890 198 : $bean->setLogger(\Logger::getLogger($class));
891 198 : }
892 276 : if ($rClass->implementsInterface('Ding\Container\IContainerAware')) {
893 276 : $bean->setContainer($this);
894 276 : }
895 276 : if ($rClass->implementsInterface('Ding\Resource\IResourceLoaderAware')) {
896 272 : $bean->setResourceLoader($this);
897 272 : }
898 276 : if ($rClass->implementsInterface('Ding\Aspect\IAspectManagerAware')) {
899 276 : $bean->setAspectManager($this->_aspectManager);
900 276 : }
901 :
902 276 : if ($rClass->implementsInterface('Ding\Bean\IBeanDefinitionProvider')) {
903 276 : $this->registerBeanDefinitionProvider($bean);
904 276 : }
905 276 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterConfigListener')) {
906 276 : $this->_lifecycleManager->addAfterConfigListener($bean);
907 276 : }
908 276 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterDefinitionListener')) {
909 272 : $this->_lifecycleManager->addAfterDefinitionListener($bean);
910 272 : }
911 276 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeCreateListener')) {
912 1 : $this->_lifecycleManager->addBeforeCreateListener($bean);
913 1 : }
914 276 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterCreateListener')) {
915 272 : $this->_lifecycleManager->addAfterCreateListener($bean);
916 272 : }
917 276 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeAssembleListener')) {
918 1 : $this->_lifecycleManager->addBeforeAssembleListener($bean);
919 1 : }
920 276 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterAssembleListener')) {
921 1 : $this->_lifecycleManager->addAfterAssembleListener($bean);
922 1 : }
923 276 : if ($rClass->implementsInterface('Ding\Aspect\IAspectProvider')) {
924 197 : $this->_aspectManager->registerAspectProvider($bean);
925 193 : }
926 276 : if ($rClass->implementsInterface('Ding\Aspect\IPointcutProvider')) {
927 193 : $this->_aspectManager->registerPointcutProvider($bean);
928 193 : }
929 276 : }
930 :
931 : /**
932 : * Called when a signal is caught.
933 : *
934 : * @param integer $signo
935 : *
936 : * @return void
937 : */
938 : public function signalHandler($signo)
939 : {
940 2 : $msg = "Caught Signal: $signo";
941 2 : $this->_logger->warn($msg);
942 2 : $this->eventDispatch('dingSignal', $signo);
943 2 : }
944 :
945 : /**
946 : * Called by php after set_error_handler()
947 : *
948 : * @param integer $type
949 : * @param string $message
950 : * @param string $file
951 : * @param integer $line
952 : *
953 : * @return true
954 : */
955 : public function errorHandler($type, $message, $file, $line)
956 : {
957 11 : $msg = "$message in $file:$line";
958 11 : if ($msg == $this->_lastErrorMessage) {
959 1 : return;
960 : }
961 11 : $this->_lastErrorMessage = $msg;
962 11 : $this->_logger->error($msg);
963 11 : $this->eventDispatch(
964 11 : 'dingError', new ErrorInfo($type, $message, $file, $line)
965 11 : );
966 11 : return true;
967 : }
968 :
969 : // @codeCoverageIgnoreStart
970 : /**
971 : * Called by the vm after register_shutdown_function()
972 : *
973 : * @return void
974 : */
975 : public function shutdownHandler()
976 : {
977 : $msg = "Shutting down";
978 : $this->eventDispatch('dingShutdown');
979 : }
980 : // @codeCoverageIgnoreEnd
981 :
982 : /**
983 : * (non-PHPdoc)
984 : * @see Ding\Container.IContainer::registerProperties()
985 : */
986 : public function registerProperties(array $properties)
987 : {
988 276 : foreach ($properties as $key => $value) {
989 48 : if (strncmp($key, 'php.', 4) === 0) {
990 2 : ini_set(substr($key, 4), $value);
991 2 : }
992 48 : $this->_properties['${' . $key . '}'] = $value;
993 276 : }
994 276 : }
995 :
996 : /**
997 : * Constructor.
998 : *
999 : * @param array $options options.
1000 : *
1001 : * @return void
1002 : */
1003 : protected function __construct(array $options)
1004 : {
1005 : // Setup logger.
1006 276 : $this->_logger = \Logger::getLogger(get_class($this));
1007 276 : $this->_logDebugEnabled = $this->_logger->isDebugEnabled();
1008 276 : $soullessArray = array();
1009 276 : $this->_beanAliases = $soullessArray;
1010 276 : $this->_beanDefs = $soullessArray;
1011 276 : $this->_beans = $soullessArray;
1012 276 : $this->_shutdowners = $soullessArray;
1013 276 : $this->_resources = $soullessArray;
1014 276 : $this->_eventListeners = $soullessArray;
1015 276 : $this->_properties = $soullessArray;
1016 :
1017 : // Merge options with our defaults.
1018 276 : self::$_options = array_replace_recursive(self::$_options, $options);
1019 276 : $this->registerProperties(self::$_options['properties']);
1020 276 : $sapi = php_sapi_name();
1021 276 : if ($sapi == 'cgi' || $sapi == 'cli') {
1022 276 : $handler = array($this, 'signalHandler');
1023 276 : foreach ($this->_signals as $signal) {
1024 276 : pcntl_signal($signal, $handler);
1025 276 : }
1026 276 : pcntl_sigprocmask(SIG_UNBLOCK, $this->_signals);
1027 276 : }
1028 276 : set_error_handler(array($this, 'errorHandler'));
1029 276 : register_shutdown_function(array($this, 'shutdownHandler'));
1030 :
1031 276 : $this->_lifecycleManager = new BeanLifecycleManager;
1032 276 : $this->_dispatcherTemplate = new DispatcherImpl();
1033 276 : $this->_aspectManager = new AspectManager();
1034 276 : $this->_beanDefCache = DummyCacheImpl::getInstance();
1035 276 : $this->_beanCache = DummyCacheImpl::getInstance();
1036 276 : $this->registerBeanDefinitionProvider(new Core(self::$_options));
1037 276 : $this->_reflectionFactory = $this;
1038 276 : $this->_reflectionFactory = $this->getBean('dingReflectionFactory');
1039 276 : $this->_proxyFactory = $this->getBean('dingProxyFactory');
1040 276 : $this->_beanDefCache = $this->getBean('dingDefinitionsCache');
1041 276 : $this->_beanCache = $this->getBean('dingBeanCache');
1042 276 : $this->_lifecycleManager = $this->getBean('dingLifecycleManager');
1043 276 : $this->_aspectManager = $this->getBean('dingAspectManager');
1044 276 : $this->_dispatcherTemplate = $this->getBean('dingAspectCallDispatcher');
1045 :
1046 : // Set drivers
1047 276 : if (isset(self::$_options['bdef']['xml'])) {
1048 169 : $xmlDriver = $this->getBean('dingXmlBeanDefinitionProvider');
1049 167 : }
1050 274 : if (isset(self::$_options['bdef']['yaml'])) {
1051 38 : $yamlDriver = $this->getBean('dingYamlBeanDefinitionProvider');
1052 36 : }
1053 272 : $this->getBean('dingPropertiesDriver');
1054 272 : $this->getBean('dingMessageSourceDriver');
1055 272 : $this->getBean('dingMethodInjectionDriver');
1056 :
1057 : // All set, continue.
1058 272 : if (isset(self::$_options['bdef']['annotation'])) {
1059 110 : $this->getBean('dingAnnotationDiscovererDriver');
1060 110 : $this->getBean('dingAnnotationBeanDefinitionProvider');
1061 110 : $this->getBean('dingAnnotationValueDriver');
1062 110 : $this->getBean('dingAnnotationAspectDriver');
1063 110 : $this->getBean('dingAnnotationResourceDriver');
1064 110 : $this->getBean('dingAnnotationInitDestroyMethodDriver');
1065 110 : $this->getBean('dingAnnotationRequiredDriver');
1066 110 : $this->getBean('dingMvcAnnotationDriver');
1067 110 : }
1068 272 : $this->_lifecycleManager->afterConfig();
1069 272 : }
1070 : }
|